package com.mainbo.core.filter;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mainbo.core.common.constant.ApolloConstants;
import com.mainbo.core.common.constant.UserToken;
import com.mainbo.core.shiro.SessionKey;
import com.mainbo.core.shiro.ShiroKit;
import com.mainbo.modular.system.dao.PtAccountMapper;
import com.mainbo.modular.system.dao.PtAreaMapper;
import com.mainbo.modular.system.dao.PtOrgMapper;
import com.mainbo.modular.system.model.*;
import com.mainbo.modular.system.service.IPtOrgRelationshipService;
import com.mainbo.modular.system.service.IPtOrgService;
import com.mainbo.platform.uc.client.DefaultLoginSuccessCallback;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author moshang
 * @date 2020-03-15
 **/
public class MainboLoginSuccessCallback extends DefaultLoginSuccessCallback {


    @Resource
    private PtAccountMapper accountMapper;

    private static final Logger logger = LoggerFactory.getLogger(MainboLoginSuccessCallback.class);

    /**
     * 登录回调 可用于记录应用系统的相关登录状态
     *
     * @param principal
     *          登录认证id，一般为用户id
     * @param infos
     *          平台登录后的用户信息，参考平台登录信息规范
     */
    @Override
    protected void invokeSuccess(Object principal, Map<String, Object> infos, ServletRequest request,
                                 ServletResponse response) {
        String userid = (String) principal;
        if (userid != null && ShiroKit.getSessionAttr(SessionKey.CURRENT_USER) == null) {
            fillSession(infos);
        }
    }

    private void fillSession(Map<String, Object> infos) {
        if ( infos == null) {
            return;
        }
        PtAccount account = new PtAccount();
        try {
            account = accountMapper.selectById((String) infos.get("id"));
        } catch (Exception e) {
            fillAttrs(account, infos);
        }
        CommUser commuser = new CommUser();
        fillAttrs(commuser, infos);
        account.setUserInfo(commuser);

        ShiroKit.setSessionAttr(SessionKey.CURRENT_USER, account);

        JSONArray roles = (JSONArray) infos.get("roles");
        if (roles != null && roles.size() > 0) {
            JSONObject jrole = (JSONObject) roles.get(0);
            PtUserRole userRole = new PtUserRole();
            userRole.setRoleId(jrole.getInteger("roleId"));
            userRole.setPhaseId(jrole.getInteger("phaseId"));
            userRole.setGradeId(jrole.getInteger("gradeId"));
            userRole.setSubjectId(jrole.getInteger("subjectId"));
            userRole.setAccountId(account.getId());
            userRole.setSysRoleId(jrole.getInteger("roleId"));
            userRole.setName(jrole.getString("name"));
            ShiroKit.setSessionAttr(SessionKey.CURRENT_USER_ROLE, userRole);
        }
    }

    private void fillAttrs(Object o, Map<String, Object> infos) {
        for (Method method : o.getClass().getDeclaredMethods()) {
            if (method.getName().startsWith("set") && method.getParameterTypes().length == 1
                    && Modifier.isPublic(method.getModifiers())) {
                try {
                    String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase()
                            + method.getName().substring(4) : "";
                    Object value = infos.get(property);
                    if (Date.class.isAssignableFrom(method.getParameterTypes()[0]) && value instanceof Number) {
                        value = new Date(((Number) value).longValue());
                    }
                    if (value != null) {
                        method.invoke(o, value);
                    }
                } catch (Exception e) {
                    logger.warn("fail to inject via method " + method.getName() + " of interface " + o.getClass().getName()
                            + ": " + e.getMessage(), e);
                }
            }
        }
    }
}
